/**
 * Copyright (C), 2017-2018, XXX有限公司
 * FileName: StatementWave
 * Author:   zengjian
 * Date:     2018/9/28 11:58
 * Description: 语法(抽象树节点解析)
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
package org.yinxue.swing.unit.ast.token;

import org.yinxue.swing.unit.ast.node.*;

import java.util.Deque;
import java.util.LinkedList;
import java.util.List;

/**
 * 〈语法(抽象树节点解析)〉<br>
 * 〈一句话描述〉
 *
 * @author zengjian
 * @create 2018/9/28 11:58
 */
public class StatementWave {

    private List<String> tokens;
    private int size;
    private int offset = size;

    private Node classNode;

    /**
     * 构造一个目前正在操作的队列
     */
    private Deque<Node> scopeStack = new LinkedList<>();
    private Deque<Node> statementStack = new LinkedList<>();

    /**
     * 大括号层级,最外层层级为0,遇见第一个结束 } ，层级+1，遇见 { 层级-1
     */
    private int braceLevel = 0;

    /**
     * 节点处理监听类
     */
    private NodeWave nodeWave = new NodeWave();

    public void fireStatementEvent(TokenEvent tokenEvent) {
        tokens = tokenEvent.getTokens();
        size = tokens.size();
        combineStatements();
        fireNodeEvent();
    }


    /**
     * 从后往前开始解析tokens流
     */
    private void combineStatements() {
        // 解析前先创建一个ClassNode,层级为0, end为size start为0
        classNode = new ClassNode().braceLevel(braceLevel).end(size).start(0).tokens(tokens);
        // 将正在操作的节点push到栈中，表明目前操作的节点是哪个
        scopeStack.push(classNode);
        resolveNode();
    }

    private void resolveNode() {
        for (int i = size - 1; i >= 0; i--) {
            String token = tokens.get(i);
            try {
                // 第一个 }

                // 当遇见 } 时，可以确认通过栈来确定父类，确认end下标，当遇见 { 可以确认node的start下标
                if ("}".equals(token)) {


                    braceLevel++;
                    // 从栈中取得，在 { 的时候进行出栈
                    Node node = new BodyNode().braceLevel(braceLevel).parent(scopeStack.peek()).end(i + 1).tokens(tokens);
                    scopeStack.push(node);
                } else if ("{".equals(token)) {
                    braceLevel--;
                    Node node = scopeStack.pop();
                    node.start(i + 1);
                    // 同时下标需要跳转到下一个 { } ; 为止，获取上一个关联的语句节点
                    if (node instanceof BodyNode) {
                        BodyNode bodyNode = (BodyNode) node;
                        Node headerNode = new HeaderNode().braceLevel(braceLevel).parent(scopeStack.peek()).end(i + 1).tokens(tokens);
                        for (int j = i - 1; j >= 0; j--) {
                            String token2 = tokens.get(j);
                            if (token2.equals("{") || token2.equals("}") || token2.equals(";") || j == 0) {
                                headerNode.start(j + 1);
                                i = j + 1;
                                break;
                            }
                        }
                        bodyNode.header(headerNode);
                    }
                } else if (";".equals(token)) {
                    // 从;开始，遇见另外一个; { ) 或者是下标为0时结束 并且需要拥有相同的层级
                    int currentBraceLevel = braceLevel;
                    Node node = new StatementNode().braceLevel(currentBraceLevel).parent(scopeStack.peek()).end(i + 1).tokens(tokens);
                    for (int j = i - 1; j >= 0; j--) {
                        String token2 = tokens.get(j);
                        if (token2.equals(";") || token2.equals("}") || token2.equals("{") || /*token2.equals(")") ||*/ j == 0) {
                            // 如果到了package语句，start需要设置为0
                                node.start(j == 0 ? 0 : j + 1);
                                i = j + 1;
                                break;
                        }
                    }
                }
            } catch (Exception e) {
                // 排错用
                e.printStackTrace();
                System.out.println(i);
                System.out.println(tokens.get(i - 1));
                System.out.println(token);
                System.out.println(tokens.get(i + 1));
                System.out.println(tokens.get(i + 2));
                System.out.println(tokens.get(i + 3));
            }
        }
    }


    private void fireNodeEvent() {
        if (classNode != null) {
            nodeWave.fireNodeEvent(new NodeEvent(this, classNode));
        }
    }

}